﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace SBPweb.RIA.Client.Controls.Themes
{

    public class CssApplier
    {

        private List<Rule> rules = new List<Rule>();

        public CssApplier()
        {
        }

        public event DownloadStringCompletedEventHandler StyleLoaded;

        public void LoadStylesheet(string cssUrl)
        {
            WebClient wc = new WebClient();
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(this.Style_Downloaded);
            wc.DownloadStringAsync(new Uri(cssUrl));
        }

        private void Style_Downloaded(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error == null && !e.Cancelled)
            {
                rules.Clear();

                string[] rls = e.Result.Split('}');
                for (int i = 0; i < rls.Length; i++)
                {
                    string strRule = rls[i];
                    strRule = Regex.Replace(strRule, @"\/\*.*?(?=\*\/)\*\/", "", RegexOptions.Singleline); //Remove Comments
                    strRule = strRule.Trim();
                    if (!String.IsNullOrEmpty(strRule) && strRule.StartsWith("#"))
                    {
                        string ruleName = strRule.Substring(1, strRule.IndexOf('{') - 1).Trim();
                        string[] props = strRule.Substring(strRule.IndexOf('{') + 1).Trim().Split(';');
                        Rule rule = new Rule(ruleName, props.Length - 1);
                        for (int j = 0; j < props.Length - 1; j++)
                        {
                            string[] arr = props[j].Split(':');
                            string propName = arr[0].Trim().ToLower();
                            string propVal = arr[1].TrimEnd(';').Trim().Replace(" ", "").Replace("px", "");

                            switch (propName)
                            {
                                case "left":
                                    rule.Setters[j] = new Setter(Canvas.LeftProperty, double.Parse(propVal));
                                    break;
                                case "top":
                                    rule.Setters[j] = new Setter(Canvas.TopProperty, double.Parse(propVal));
                                    break;
                                case "width":
                                    rule.Setters[j] = new Setter(FrameworkElement.WidthProperty, double.Parse(propVal));
                                    break;
                                case "height":
                                    rule.Setters[j] = new Setter(FrameworkElement.HeightProperty, double.Parse(propVal));
                                    break;
                                case "font-family":
                                    rule.Setters[j] = new Setter(TextBlock.FontFamilyProperty, new FontFamily(propVal));
                                    break;
                                case "font-size":
                                    rule.Setters[j] = new Setter(TextBlock.FontSizeProperty, double.Parse(propVal));
                                    break;
                                case "opacity":
                                    rule.Setters[j] = new Setter(FrameworkElement.OpacityProperty, double.Parse(propVal));
                                    break;
                                case "border-color":
                                    rule.Setters[j] = new Setter(Shape.StrokeProperty, new SolidColorBrush(HexToRgbColor(propVal)));
                                    break;
                                case "background-color":
                                    rule.Setters[j] = new Setter(Shape.FillProperty, new SolidColorBrush(HexToRgbColor(propVal)));
                                    break;
                                case "visibility":
                                    if (propVal.ToLower() == "visible" || propVal.ToLower() == "collapsed")
                                    {
                                        Visibility v = (Visibility)Enum.Parse(typeof(Visibility), propVal, true);
                                        rule.Setters[j] = new Setter(FrameworkElement.VisibilityProperty, v);
                                    }
                                    break;
                            }
                        }
                        rules.Add(rule);
                    }
                }
            }

            if (StyleLoaded != null)
            {
                StyleLoaded(sender, e);
            }
        }

        public void ApplyToCanvas(Canvas canvas)
        {
            foreach (Rule rule in rules)
            {
                object obj = canvas.FindName(rule.Name);
                if (obj == null)
                    continue;

                DependencyObject dp = obj as DependencyObject;
                if (dp != null)
                {
                    for (int i = 0; i < rule.Setters.Length; i++)
                    {
                        dp.SetValue(rule.Setters[i].Property, rule.Setters[i].Value);
                    }
                }
            }
        }

        private Color HexToRgbColor(string hex)
        {
            hex = hex.TrimStart('#');
            int r, g, b;
            int num = (int)long.Parse(hex, System.Globalization.NumberStyles.HexNumber);
            r = (num & 0xFF0000) >> 16;
            g = (num & 0xFF00) >> 8;
            b = num & 0xFF;
            return Color.FromArgb(255, (byte)r, (byte)g, (byte)b);
        }


        private class Rule
        {

            public Rule(string name, int setterLength)
            {
                Name = name;
                Setters = new Setter[setterLength];
            }

            public string Name
            {
                get;
                private set;
            }

            public Setter[] Setters
            {
                get;
                private set;
            }

        }
    
    }

}
